/**
 * 
 */
package com.cipe.cmrs.controllers.payment;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

import com.cipe.cmrs.bean.CipeprojectBean;
import com.cipe.cmrs.bean.CodeDescriptionBean;
import com.cipe.cmrs.bean.PaymentRequestBean;
import com.cipe.cmrs.controllers.BaseController;
import com.cipe.cmrs.converter.DateEditor;
import com.cipe.cmrs.model.Country;
import com.cipe.cmrs.model.Payee;
import com.cipe.cmrs.model.Paymenttype;
import com.cipe.cmrs.model.User;
import com.cipe.cmrs.service.AccountCodeService;
import com.cipe.cmrs.service.CipeprojectService;
import com.cipe.cmrs.service.CountryService;
import com.cipe.cmrs.service.PayeeService;
import com.cipe.cmrs.service.PaymentrequestService;
import com.cipe.cmrs.service.PaymentrequestlineitemService;
import com.cipe.cmrs.service.PaymenttypeService;
import com.cipe.cmrs.service.UserService;
import com.cipe.cmrs.util.Constants;
import com.cipe.cmrs.util.CustomTimestampEditor;
import com.cipe.cmrs.validator.PaymentRequestValidator;

/**
 * @author Incepio
 * 
 */
public abstract class AbstractPaymentController extends BaseController {
    /**
	 * 
	 */
    private static final long serialVersionUID = 2071110718678373348L;
    protected static final String COMMAND_NAME = "paymentrequest";
    @Autowired
    protected PaymentrequestService paymentrequestService;
    @Autowired
    protected CountryService countryService;
    @Autowired
    protected PaymenttypeService paymenttypeService;
    @Autowired
    protected UserService userService;
    @Autowired
    private PaymentrequestlineitemService lineItemService;
    @Autowired
    protected PayeeService payeeService;
    @Autowired
    protected CipeprojectService cipeprojectService;
    @Autowired
    protected AccountCodeService accountCodeService;
    @Autowired
    protected PaymentRequestValidator validator;

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Timestamp.class, new CustomTimestampEditor(Constants.DefaultDateFormat));
        binder.registerCustomEditor(java.util.Date.class, new DateEditor(Constants.DefaultDateFormat, Constants.DefaultDateFormat));
    }

    @RequestMapping(method = RequestMethod.GET)
    protected ModelAndView getFormView(@ModelAttribute(COMMAND_NAME) PaymentRequestBean paymentRequest, HttpServletRequest request) {
        return new ModelAndView(getFormView()).addAllObjects(getReferenceData(paymentRequest, request));
    }

    protected ModelAndView getSuccessView(PaymentRequestBean paymentRequest, HttpServletRequest request) {
        return new ModelAndView(getSuccessView()).addAllObjects(getReferenceData(paymentRequest, request));
    }

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView onSubmit(@ModelAttribute(COMMAND_NAME) PaymentRequestBean bean, BindingResult result,
        HttpServletRequest request, SessionStatus status) {
        ModelAndView mav = null;
        validator.validate(result, bean);
        if (result.hasErrors()) {
            mav = getFormView(bean, request);
            mav.addAllObjects(result.getModel());
            saveError(request, result.getGlobalErrors());
        } else {
            try {
                String nextAction = request.getParameter(getText("name.button.nextaction"));
                if (StringUtils.hasText(nextAction)) {
                    bean = paymentrequestService.processPaymentRequest(bean, getUserId(request));
                } else {
                    String action = request.getParameter(DEFAULT_SUBMIT_NAME);
                    if (getText("editPaymentrequest.label.cancel").equalsIgnoreCase(action)) {
                        bean = paymentrequestService.cancelPaymentRequest(bean, getUserId(request), null);
                    } else if (getText("editPaymentrequest.label.reject").equalsIgnoreCase(action)) {
                        bean = paymentrequestService.rejectPaymentRequest(bean, getUserId(request));
                    } else if (getText("editPaymentrequest.label.prResubmit").equals(action)) {
                        bean = paymentrequestService.resubmitPayment(bean, getUserId(request));
                    } else if (getText("editPaymentrequest.label.prCancel").equalsIgnoreCase(action)) {
                        bean = paymentrequestService.setCancelRequested(bean, getUserId(request));
                    } else {
                        bean = paymentrequestService.savePaymentrequest(bean, getUserId(request));
                    }
                }

                saveMessage(request, getText("editPaymentrequest.message.success"));
                status.setComplete();
                mav = getSuccessView(bean, request).addObject(COMMAND_NAME, bean);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(getText("error.transaction"), e);
                saveError(request, getText("error.transaction"));
                mav = getFormView(bean, request);
            }
        }
        return mav;
    }

    protected Map<String, Object> getReferenceData(PaymentRequestBean paymentRequest, HttpServletRequest request) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("cipeProjects", getAllCipeProjects(paymentRequest.getId()));
        map.put("accountCodes", getAllAccountCodes());
        map.put("currentUserId", getUserId(request));
        map.put("countryList", getAllCountries());
        map.put("userList", getAllUsers());
        map.put("payeeList", getAllPayees());
        map.put("paymenttypeList", getActivePaymentTypes());
        return map;
    }

    public List<CipeprojectBean> getAllCipeProjects(Integer excludePaymentRequest) {
        List<String> columns = new ArrayList<String>();
        columns.add("projectTitle");
        columns.add("costCenterNumber");
        columns.add("id");
        columns.add("projectID");
        columns.add("cipeprojecttype.displayName");
        columns.add("cipeprojectstatus.displayName");
        columns.add("region.displayName");
        columns.add("country.displayName");
        columns.add("acronym");
        columns.add("projectStartDate");
        columns.add("projectEndDate");
        columns.add("partner.partnerName");
        columns.add("override");
        columns.add("managementFunds");
        columns.add("partnerGrantFunds");
        List<CipeprojectBean> beans = cipeprojectService.getAllActiveCipeProjects(columns);
        for (CipeprojectBean bean : beans) {
            bean.setRemainingFunds(getRemainingFunds(bean, excludePaymentRequest));
        }
        return beans;
    }

    private BigDecimal getRemainingFunds(CipeprojectBean project, Integer excludePaymentRequest) {
        BigDecimal remainingFunds = BigDecimal.ZERO;
        remainingFunds = project.getManagementFunds();
        remainingFunds = remainingFunds.add(project.getPartnerGrantFunds());
        BigDecimal deductedAmounts = lineItemService.getProjectTotalAmount(excludePaymentRequest, project.getId());
        remainingFunds = remainingFunds.subtract(deductedAmounts);
        return remainingFunds;
    }

    public List<CodeDescriptionBean> getAllAccountCodes() {
        return accountCodeService.getAllAccountCodeBeans(Arrays.asList("id", "accountCode", "description"));
    }

    public Integer getUserId(HttpServletRequest request) {
        return getUserId(request.getSession());
    }

    public List<Country> getAllCountries() {
        return countryService.getAllCountries();
    }

    public List<Paymenttype> getActivePaymentTypes() {
        return paymenttypeService.getActivePaymentTypes();
    }

    public List<User> getAllUsers() {
        return userService.findAll();
    }

    public List<Payee> getAllPayees() {
        return payeeService.getAllActivePayees();
    }

}
